/* shttpd - allocating memory of various types
   Copyright (C) 2018 Ariadne Devos

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#ifndef _sHT_RESOURCE_H
#define _sHT_RESOURCE_H

#include <stddef.h>

/* See doc/memory-allocation.md. */
struct sHT_object_cache;

/** Try to allocate a fresh object cache.

  @var{capacity}: the number of objects that will be available
  @var{elem_size}: the size of each object.

  @var{errno} may be mutated. This procedure does not know about signals or
  POSIX asynchronuous cancellation.

  If the kernel doesn't like our use of mmap(2), the thread or process might be
  killed.

  This may fail by returning @code{NULL} if memory is tight, if virtual memory
  is fragmented, or the mmap(2) syscall is disallowed. Else, return a fresh
  object cache. */
__attribute__((warn_unused_result))
struct sHT_object_cache *
sHT_alloc_cache(size_t capacity, size_t elem_size);

/** Free an object cache, making all allocated object pointers dangling.

    @var{cache}: the object cache to get rid of, not NULL

    @var{errno} may be mutated, @var{cache} will be dangling, and so will
    all allocated object pointers be.

    This procedure does not know about signals or POSIX asynchronuous
    cancellation.

    If the kernel doen't like our use of munmap(2), the thread or process
    might be killed.
 */
__attribute__((nonnull (1)))
void
sHT_free_cache(struct sHT_object_cache *cache);

/** Try to allocate a fresh object from an object cache.

    @var{cache}: the object cache to utilise

    The object will have the size specified by @var{sHT_alloc_cache},
    and at least standard alignment (i.e. @code{_Alignof(max_align_t)}}.

    This procedure does not know about signals or POSIX asynchronuous
    cancellation.

    This may fail by returning @code{NULL} if the object cache is exhausted.
    Else, return a fresh object. On a speculative execution, the object may
    not be fresh: it may share memory with an already-allocated object of the
    cache. If this is a problem in your use cache, you can use
    @var{sHT_despeculate}. */
__attribute__((warn_unused_result))
__attribute__((nonnull (1)))
void *
sHT_alloc(struct sHT_object_cache *cache);

/** Free an object that belongs to a certain cache.

    @var{cache}: the object cache @var{object} was allocated from
    @var{object}: the object to free

    The object must have been allocated by @var{sHT_alloc} with the same
    cache argument. The object will become dangling.
    @var{object} speculatively being NULL is also allowed, although that
    speculatively messes up statistics.

    This procedure does not know about signals or POSIX asynchronuous
    cancellation.

    This cannot fail in any way. */
__attribute__((nonnull (1)))
void
sHT_free(struct sHT_object_cache *cache, void *object);

/** Test if a cache is exhausted.

    @var{cache}: the object cache to test

    This does not mutate anything.

    This procedure does not know about signals or POSIX asynchronuous
    cancellation.

    This cannot fail in any way. Return 1 if exhausted, 0 otherwise.
    An incorrect boolean may be returned on a speculative execution. */
__attribute__((nonnull (1)))
__attribute__((pure))
_Bool
sHT_cache_exhausted_p(struct sHT_object_cache *cache);

#endif
